using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Reflection;
using System.Text;
using System.Threading;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Workflows.Components.Communication;
using Microsoft.Office.Interop.Outlook;
using Attachment=System.Net.Mail.Attachment;
using Exception=System.Exception;

namespace Workflows.Components.Communication
{
    /// <summary>
    /// 
    /// </summary>
    public class EmailWorker:IWorker
    {
        private Thread _WorkerThread;
        private EmailInstruction _Instruction;
        private EmailOutput _Output;
        private Guid _TicketID;
        private RunContext _Context;
        private string _WorkflowName;
        private string _ComponentName;

        /// <summary>
        /// 
        /// </summary>
        public string ComponentName
        {
            get { return _ComponentName; }
        }

        /// <summary>
        /// 
        /// </summary>
        public string WorkflowName
        {
            get { return _WorkflowName; }
        }

        public Thread WorkerThread
        {
            get { return _WorkerThread; }
        }

        public InstructionBase Instruction
        {
            get { return _Instruction; }
        }

        public ResultBase Output
        {
            get { return _Output; }
        }

        public Type ComponentType
        {
            get { return typeof(EmailComponent); }
        }

        public RunContext Context
        {
            get { return _Context; }
            set { _Context = value; }
        }

        public void SetInstruction(Guid ticketGuid, InstructionBase request, string workflowName, string componentName)
        {
            this._TicketID = ticketGuid;
            this._Instruction = (EmailInstruction) request;
            this._WorkflowName = workflowName;
            this._ComponentName = componentName;
        }

        public void SetInstruction(RunContext context, Guid ticketGuid, InstructionBase request, string workflowName, string componentName)
        {
            this._Context = context;
            this._TicketID = ticketGuid;
            this._Instruction = (EmailInstruction) request;
            this._WorkflowName = workflowName;
            this._ComponentName = componentName;
        }

        public void DoWork()
        {
            if(this.WorkerStartedEvent !=null)
            {
                this.WorkerStartedEvent(this._TicketID, this, this.GetType(), this._Instruction);
            }
            this._WorkerThread = Thread.CurrentThread;
            this.SendEmail();
        }

        public void DoWorkAsync()
        {
            if (this.WorkerStartedEvent != null)
            {
                this.WorkerStartedEvent(this._TicketID, this, this.GetType(), this._Instruction);
            }
            this._WorkerThread = new Thread(new ThreadStart(this.SendEmail));
            this._WorkerThread.Start();
        }

        public void CancelWork()
        {
            if(this._WorkerThread !=null && this._WorkerThread.IsAlive)
            {
                this._WorkerThread.Abort();

                if(this.WorkerCancelledEvent !=null)
                {
                    this.WorkerCancelledEvent(this._TicketID, this.GetType(), this._Instruction);
                }
            }
        }

        public event WorkerStarted WorkerStartedEvent;
        public event WorkerFinished WorkerFinishedEvent;
        public event WorkerHasError WorkerErredEvent;
        public event WorkerCancelled WorkerCancelledEvent;
        public event WorkerStatusChanged WorkerStatusChangedEvent;

        #region work
        private void SendEmail()
        {
            try
            {
                if(this._Instruction.UseOutlookClient)
                {
                    this.SendEmailViaOutlook();
                }
                else
                {
                    MailMessage message = new MailMessage();
                    message.From = new MailAddress(this._Instruction.From);
                    string[] toAddresses = this._Instruction.To.Split(new char[] {',', ';'});
                    foreach (string toAddr in toAddresses)
                    {
                        message.To.Add(new MailAddress(toAddr));
                    }
                    if(!string.IsNullOrEmpty(this._Instruction.CC))
                    {
                        string[] ccAddresses = this._Instruction.CC.Split(new char[] {',', ';'});
                        foreach(string ccAddr in ccAddresses)
                        {
                            message.CC.Add(new MailAddress(ccAddr));
                        }
                    }
                    message.Subject = this._Instruction.Subject;
                    string body = this._Instruction.BodyTemplate;
                    if(this._Instruction.BodyPlaceHolders !=null && this._Instruction.BodyPlaceHolders.Count>0)
                    {
                        foreach(string name in this._Instruction.BodyPlaceHolders.Keys)
                        {
                            string val = this._Instruction.BodyPlaceHolders[name];
                            if(val==null)
                                val = string.Empty;
                            body = body.Replace("@[" + name + "]", val);
                            body = body.Replace("${" + name + "}", val);
                        }
                    }
                    message.Body = body;
                    message.Priority = this._Instruction.Priority;
                    message.IsBodyHtml = true;
                    SmtpClient smtp = new SmtpClient(this._Instruction.SmtpServer);
                    if (this._Instruction.RequireAuthentication)
                    {
                        smtp.Credentials = new NetworkCredential(this._Instruction.UserName, this._Instruction.Password);
                    }
                    if (this.WorkerStatusChangedEvent != null)
                    {
                        this.WorkerStatusChangedEvent(this._TicketID, this.GetType(), this._Instruction, this.WorkflowName, this.ComponentName,
                                                      "Sending email message...", 15);
                    }
                    if (this._Instruction.EnableSSL)
                    {
                        smtp.EnableSsl = true;
                    }

                    // attachment 
                    if(this._Instruction.Attachments !=null && this._Instruction.Attachments.Length>0)
                    {
                        foreach(string filePath in this._Instruction.Attachments)
                        {
                            if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
                            {
                                string attachmentError = string.Format("Attachment file is not found");
                                if (this.WorkerErredEvent != null)
                                {
                                    this.WorkerErredEvent(this._TicketID, this.GetType(), this._Instruction,
                                                          attachmentError, false);
                                }
                            }
                            else
                            {
                                message.Attachments.Add(new Attachment(filePath));
                            }
                        }
                    }
                    smtp.Send(message);
                }

                this._Output = new EmailOutput(this._Instruction.OwnerComponentID, this._TicketID);
                if (this.WorkerFinishedEvent != null)
                {
                    this.WorkerFinishedEvent(this._TicketID, this.GetType(), this._Instruction, this._Output);
                }
            }
            catch(Exception ex)
            {
                if(this.WorkerErredEvent !=null)
                {
                    this.WorkerErredEvent(this._TicketID, this.GetType(), this._Instruction, ex.ToString(),true);
                }
            }
        }

        private void SendEmailViaOutlook()
        {
            
            Application olApp = new Application();
            // Get the NameSpace and Logon information.
            NameSpace olNamespace = olApp.GetNamespace("mapi");

            // Log on by using a dialog box to choose the profile.
            olNamespace.Logon(Missing.Value, Missing.Value, true, true);

            MailItem mailItem = (MailItem) olApp.CreateItem(OlItemType.olMailItem);
            mailItem.BodyFormat = OlBodyFormat.olFormatHTML;
            // attachments 
            if (this._Instruction.Attachments != null)
            {
                foreach (string filePath in this._Instruction.Attachments)
                {
                    string fileName = Path.GetFileName(filePath);
                    mailItem.Attachments.Add(filePath, null, null, fileName);
                }
            }
            mailItem.Display(false);
            mailItem.Importance = OlImportance.olImportanceNormal;
            if (this._Instruction.Priority == MailPriority.High)
            {
                mailItem.Importance = OlImportance.olImportanceHigh;
            }
            else if (this._Instruction.Priority == MailPriority.Low)
            {
                mailItem.Importance = OlImportance.olImportanceLow;
            }
            mailItem.Subject = this._Instruction.Subject;
            string body = this._Instruction.BodyTemplate;
            if (this._Instruction.BodyPlaceHolders != null && this._Instruction.BodyPlaceHolders.Count > 0)
            {
                foreach (string name in this._Instruction.BodyPlaceHolders.Keys)
                {
                    string val = this._Instruction.BodyPlaceHolders[name];
                    if (val == null)
                        val = string.Empty;
                    body = body.Replace("@[" + name + "]", val);
                    body = body.Replace("${" + name + "}", val);
                }
            }
            mailItem.HTMLBody = body;
            string[] toAddresses = this._Instruction.To.Split(new char[] {',', ';'});
            foreach (string toAddr in toAddresses)
            {
                mailItem.Recipients.Add(toAddr);
            }
            if(!string.IsNullOrEmpty(this._Instruction.CC))
            {
                string[] ccAddresses = this._Instruction.CC.Split(new char[] {',', ';'});
                foreach(string ccAddr in ccAddresses)
                {
                    mailItem.CC.Insert(0, ccAddr);
                }
            }
            // mailItem.To = StringUtil.ToString(this._Instruction.To, ";");
            if(this._Instruction.Attachments !=null && this._Instruction.Attachments.Length>0)
            {
                int pos = 0;
                foreach(string filePath in this._Instruction.Attachments)
                {
                    if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
                    {
                        string attachmentError = string.Format("Attachment file is not found");
                        if (this.WorkerErredEvent != null)
                        {
                            this.WorkerErredEvent(this._TicketID, this.GetType(), this._Instruction,
                                                  attachmentError, false);
                        }
                    }
                    else
                    {
                        pos++;
                        mailItem.Attachments.Add(filePath, OlAttachmentType.olByValue, pos, Path.GetFileName(filePath));
                    }
                }
            }
            mailItem.Send();
        }
        #endregion
    }
}
